import { EventMgr } from "../event/EventMgr";
import { Cls } from "../util/Defined";
import { Logger } from "../util/Logger";
import { Rand } from "../util/Rand";
import { SeedRand } from "../util/SeedRand";
import { TypeUtil } from "../util/TypeUtil";
import { ECSEntity } from "./ECSEntity";
import { ECSEntityMgr } from "./ECSEntityMgr";
import { ECSFilterMgr } from "./ECSFilterMgr";
import { ECSSceneCmp } from "./ECSSceneCmp";
import { ECSSys } from "./ECSSys";
import { ECSSysMgr } from "./ECSSysMgr";

/**
 * 场景状态
 */
export const enum ECSSceneState {
	/** 初始化 */
	init = "init",
	/** 运行中 */
	run = "run",
	/** 暂停中 */
	pause = "pause",
	/** 已停止 */
	stop = "stop",
}

/**
 * 场景事件
 */
export enum ECSSceneEvent {
	stateChanged = "stateChanged",
	beforeUpdate = "beforeUpdate",
	afterUpdate = "afterUpdate",
	frameRateChanged = "frameRateChanged",
}

/**
 * [ECS]场景
 */
export class ECSScene extends EventMgr<ECSEventData> {
	/** 最大帧间隔 */
	maxDtMs: number;

	/** 帧速率 */
	protected _frameRate = 1;
	/** 帧速率 */
	get frameRate() {
		return this._frameRate;
	}
	set frameRate(v: number) {
		this._frameRate = v;
		this.send(ECSSceneEvent.frameRateChanged);
	}

	/** 帧间隔(秒) */
	readonly dt: number;
	/** 帧间隔(毫秒) */
	readonly dtMs: number;

	protected _state = ECSSceneState.init;
	/** 场景状态 */
	get state() {
		return this._state;
	}

	constructor(
		/** 逻辑帧率 */
		readonly fps: number
	) {
		super();
		this.dt = 1 / fps;
		this.dtMs = 1000 / fps;
		this.maxDtMs = this.dtMs * 5;
	}

	/**
	 * 启动场景
	 */
	start() {
		if (this._state === ECSSceneState.init) {
			this.onStateChange(ECSSceneState.run);
		}
	}

	/**
	 * 暂停场景
	 */
	pause() {
		if (this._state === ECSSceneState.run) {
			this.onStateChange(ECSSceneState.pause);
		}
	}

	/**
	 * 恢复场景
	 */
	resume() {
		if ((this._state = ECSSceneState.pause)) {
			this.onStateChange(ECSSceneState.run);
		}
	}

	/**
	 * 停止场景
	 */
	stop() {
		if (this._state !== ECSSceneState.stop) {
			this.onStateChange(ECSSceneState.stop);
		}
	}

	private _timer: any;
	protected _lastTime: number = 0;
	/** 上次循环剩下的dtms */
	protected _leftDtMs: number = 0;

	/**
	 * 自定义启动结束帧循环方法
	 * @param startLoop 启动帧循环 每帧调用tick()会自动根据逻辑帧率的dt去触发帧循环
	 * @param stopLoop 结束帧循环
	 */
	setCustomLoop(startLoop: (tick: () => void) => void, stopLoop: () => void) {
		this.startLoop = startLoop;
		this.stopLoop = stopLoop;
	}

	/**
	 * 启动帧循环 每tick()一次会自动根据逻辑帧率的dt去触发帧循环
	 */
	protected startLoop(tick: () => void) {
		this._lastTime = Date.now();
        this._timer = setInterval(() => tick());
	}

	/**
	 * 停止帧循环
	 */
	protected stopLoop() {
        clearInterval(this._timer);
	}

	/**
	 * 帧触发
	 */
	protected tick() {
		const now = Date.now();
		const dt = now - this._lastTime;
		this._lastTime = now;
		this.loop(dt);
	}

	/**
	 * 帧循环
	 * @param dt 帧间隔
	 */
	protected loop(dt: number) {
		dt = Math.min(this.maxDtMs, dt + this._leftDtMs);
		const dtMs = this.dtMs / this._frameRate;
		while (dt >= dtMs) {
			this.onUpdate();
			dt -= dtMs;
		}
		this._leftDtMs = dt;
	}

	// ============ 生命周期 ============

	protected _runFrame: number = 0;
	protected _runTime: number = 0;

	/** 已运行帧数 */
	get runFrame() {
		return this._runFrame;
	}

	/** 已运行时间(秒) */
	get runTime() {
		return this._runTime;
	}

	/**
	 * 场景状态改变
	 */
	protected onStateChange(state: ECSSceneState) {
		const lastState = this._state;
		this._state = state;
		switch (state) {
			case ECSSceneState.run:
				if (lastState === ECSSceneState.init) {
					this.onStart();
				}
				this.startLoop(this.tick.bind(this));
				break;
			case ECSSceneState.pause:
				this.stopLoop();
				break;
			case ECSSceneState.stop:
				this.stopLoop();
				this.onStop();
				break;
		}
		this.send(ECSSceneEvent.stateChanged, { lastState, state });
	}

	/**
	 * 场景启动时触发
	 */
	protected onStart() {
		this._cmps.forEach(cmp => cmp.onAdd());
		this.sysMgr.onStart();
	}

	/**
	 * 场景帧循环触发
	 */
	protected onUpdate() {
		this.send(ECSSceneEvent.beforeUpdate);

		++this._runFrame;
		this._runTime += this.dt;

		//更新实体/组件移除添加
		this.entityMgr.updateRemove();
		this.entityMgr.updateAdd();
		this.filterMgr.update();

		//系统循环 每轮循环都会检测组件更新
		this.sysMgr.sort();
		this.sysMgr.beforeUpdate();
		this.filterMgr.update();
		this.sysMgr.update();
		this.filterMgr.update();
		this.sysMgr.lateUpdate();

		//更新实体/组件移除
		this.entityMgr.updateRemove();
		this.filterMgr.update();
		this.entityMgr.updateFree();

		this.send(ECSSceneEvent.afterUpdate);
	}

	/**
	 * 场景停止时触发
	 */
	protected onStop() {
		this.offAll();
		this.entityMgr.destroy();
		this.filterMgr.destroy();
		this.sysMgr.destroy();
		this._cmps.forEach(cmp => cmp.onRemove());
		this._cmps.clear();
	}

	// ============ 工具 ============

	/** 日志工具 */
	readonly logger = new Logger();
	/** 种子随机数 */
	readonly seedRand = new SeedRand();
	/** 随机工具 */
	readonly rand = new Rand(this.seedRand.next.bind(this.seedRand));

	// ============ 管理器 ============

	/** 实体管理器 */
	readonly entityMgr = new ECSEntityMgr(this);
	/** 过滤器管理器 */
	readonly filterMgr = new ECSFilterMgr(this);
	/** 系统管理器 */
	readonly sysMgr = new ECSSysMgr(this);

	/**
	 * 创建一个实体
	 * @param add 是否添加到场景 默认true
	 */
	createEntity(add = true) {
		return this.entityMgr.create(add);
	}

	/**
	 * 通过实体id获取场景中的实体
	 * @param id 实体id
	 */
	getEntity(id: number) {
		return this.entityMgr.get(id);
	}

	/**
	 * 遍历场景里的实体
	 * @param each 返回true时则返回对应实体
	 */
	eachEntity(each: (entity: ECSEntity) => any) {
		return this.entityMgr.each(each);
	}

	/**
	 * 遍历寻找场景里的实体
	 * @param each 返回true时则返回对应实体
	 */
	findEntity(each: (entity: ECSEntity) => any) {
		return this.entityMgr.find(each);
	}

	/**
	 * 添加实体 在下一帧开始时才会真正被添加到场景
	 * @param entity 实体
	 */
	addEntity(entity: ECSEntity) {
		return this.entityMgr.add(entity);
	}

	/**
	 * 移除实体 在下一帧开始时才会真正从场景中移除
	 * @param entity 实体
	 */
	removeEntity(entity: ECSEntity) {
		return this.entityMgr.remove(entity);
	}

	/**
	 * 获取系统
	 * @param sysType 系统类型
	 */
	getSys(sysType: Cls<ECSSys>) {
		return this.sysMgr.get(sysType);
	}

	/**
	 * 添加系统
	 * @param sysType 系统类型
	 */
	addSys<T extends ECSSys>(sysType: Cls<T>) {
		return this.sysMgr.add(sysType);
	}

	/**
	 * 移除系统
	 * @param sys 系统
	 */
	removeSys(sys: ECSSys) {
		return this.sysMgr.remove(sys);
	}

	// ============ 场景组件 ============

	protected _cmps = new Map<Cls<ECSSceneCmp>, ECSSceneCmp>();

	/**
	 * 是否存在对应类型的场景组件
	 * @param cmpType 场景组件类型
	 */
	hasCmp(cmpType: Cls<ECSSceneCmp>) {
		return this._cmps.has(cmpType);
	}

	/**
	 * 获取场景组件
	 * @param cmpType 场景组件类型
	 */
	getCmp<T extends ECSSceneCmp>(cmpType: Cls<T>) {
		return this._cmps.get(cmpType) as T;
	}

	/**
	 * 添加场景组件
	 * 相同场景组件只会存在一个 重复添加会覆盖掉上一个
	 * @param cmpType 场景组件类型
	 */
	addCmp<T extends ECSSceneCmp>(cmp: T) {
		this._cmps.set(TypeUtil.getCls(cmp), cmp);
		cmp.scene = this;
		if (this._state != ECSSceneState.init) {
			cmp.onAdd();
		}
		return cmp as T;
	}

	/**
	 * 获取场景组件
	 * @param cmpType 场景组件类型
	 */
	removeCmp(cmp: ECSSceneCmp) {
		if (this._cmps.delete(TypeUtil.getCls(cmp))) {
			cmp.onRemove();
			return true;
		}
		return false;
	}
}

declare global {
	/** ECS事件携带数据 */
	interface ECSEventData {
		[ECSSceneEvent.stateChanged]: { lastState: ECSSceneState; state: ECSSceneState };
	}
}
